package com.file.parser;

import com.file.bo.ResponseData;
import com.file.bo.mail.CZB;
import com.file.bo.mail.CZBTran;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.NurminenDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 浙商银行pdf流水解析
 * @author anyspa
 */

@Slf4j
public class CZBPdfParser extends BasePdfParser {

    public ResponseData<String> parseCZBPdfToJson(String daId, String filePath) {
        log.info("parseCZBPdfToJson started, daId:{}", daId);
        String json = null;

        try {
            CZB czb = parseCZBPdf(filePath);
            json = JsonUtils.convertObjectToJson(czb);
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseCZBPdfToJson failed", e);
            return new ResponseData<>(json, ErrorCode.FILE_PARSE_EXCEPTION.getCode(),
                    ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseCZBPdfToJson completed, daId:{}", daId);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private CZB parseCZBPdf(String filePath) {
        CZB czb = parseCZBHeader(filePath);
        List<CZBTran> czbTrans = parseCZBTrans(filePath);
        czb.setCzbTrans(czbTrans);
        log.info("czb = " + czb);
        return czb;
    }

    private CZB parseCZBHeader(String filePath) {
        CZB czb = new CZB();
        String pdfHeaderText = parsePdfHeaderText(filePath);
        String name = pdfHeaderText.substring(pdfHeaderText.indexOf("户名：") + 3, pdfHeaderText.indexOf("账号：")).trim();
        String accountNo = pdfHeaderText.substring(pdfHeaderText.indexOf("账号：") + 3, pdfHeaderText.indexOf("起止日期：")).trim();
        String transDetailPeriod = pdfHeaderText.substring(pdfHeaderText.indexOf("起止日期：") + 5, pdfHeaderText.indexOf("查询时间：")).trim();
        String queryDate = pdfHeaderText.substring(pdfHeaderText.indexOf("查询时间：") + 5, pdfHeaderText.indexOf("交易时间")).trim();
        czb.setName(name);
        czb.setAccountNo(accountNo);
        czb.setTransDetailPeriod(transDetailPeriod);
        czb.setQueryDate(queryDate);

        return czb;
    }

    private List<CZBTran> parseCZBTrans(String filePath) {
        List<CZBTran> czbTrans = new ArrayList<>();
        // 1. 读取文件
        File pdf = new File(filePath);

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {
            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            NurminenDetectionAlgorithm detectionAlgorithm = new NurminenDetectionAlgorithm();
            Map<Integer, List<Rectangle>> detectedTables = new HashMap<>();

            // 4. 获取每页的PageIterator
            PageIterator pages = objectExtractor.extract();

            // 5. 解析每页的Rectangle(table的位置)
            while (pages.hasNext()) {
                Page page = pages.next();
                List<Rectangle> tablesOnPage = detectionAlgorithm.detect(page);
                if (tablesOnPage.size() > 0) {
                    detectedTables.put(page.getPageNumber(), tablesOnPage);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm bea = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : detectedTables.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());

                // 默认每页只有一个表格，因此获取第0个rectangle
                Rectangle rectangle = entry.getValue().get(0);
                Page area = page.getArea(rectangle.getTop(), rectangle.getLeft(), rectangle.getBottom(),
                        rectangle.getRight());

                List<Table> table = bea.extract(area);
                // 默认每页只有一个表格，因此获取第0个table
                Table t = table.get(0);

                // 每一页都需要去掉表格的header
                for (int i = 0; i < t.getRowCount(); i++) {
                    if (StringUtils.containsAny(t.getCell(i, 0).getText(false), "户名:" ,"交易时间", "查询时间")) {
                        continue;
                    }
                    CZBTran czbTran = getTransactionByTable(t, i);
                    czbTrans.add(czbTran);
                }
            }
        } catch (Exception e) {
            log.error("[OnError]parseTrans failed", e);
            throw new RuntimeException(e);
        }
        return czbTrans;
    }

    private CZBTran getTransactionByTable(Table t, int i) {
        CZBTran czbTran = new CZBTran();
        czbTran.setTranDate(t.getCell(i, 0).getText(false));
        czbTran.setTranAmount(t.getCell(i, 1).getText(false));
        czbTran.setBalance(t.getCell(i, 2).getText(false));
        czbTran.setAvailableBalance(t.getCell(i, 3).getText(false));
        czbTran.setSummary(t.getCell(i, 4).getText(false));
        czbTran.setCounterPartyAccountNumber(t.getCell(i, 5).getText(false));
        czbTran.setCounterPartyAccountName(t.getCell(i, 6).getText(false));
        czbTran.setCounterPartyBank(t.getCell(i, 7).getText(false));
        czbTran.setRemark(t.getCell(i, 8).getText(false));

        return czbTran;
    }

    public static void main(String[] args) {
        CZBPdfParser czbPdfParser = new CZBPdfParser();
        CZB czb = czbPdfParser.parseCZBPdf("D:\\data\\files\\CZB\\浙商银行.pdf");
        String json = JsonUtils.convertObjectToJson(czb);
        System.out.println(json);
    }
}
